The basic principle of instruction signatures is, while a program is in runtime, to sum the executed instructions in a checksum (signature) and to check them against reference values at prescribed positions. If branches occur in the program flowchart, which can be regarded as a graphical map of the program execution, it is possible to use signature updates in order to harmonize the signatures in two or more parallel paths of the program flowchart.
When a program (software) is executed on a computation unit (hardware), it is usually expected that the program is also actually executed in the manner intended by the compiler at the time of compiling. In reality, however, the execution of a program or of a code may deviate from the originally planned program execution. The responsibility for this lies with errors in the hardware, perturbing signals or else deliberate, malicious manipulations on the computation unit, for example. Errors in the hardware can be attributed to unwanted line shorts, line interruptions or hanging switching elements (what are known as “stuck-at faults”), for example, to cite a few frequently occurring types of hardware errors. Perturbing signals can arise during the operation of the computation unit, for example as a result of electromagnetic fields or else in the form of extreme temperatures which are outside of the temperature range intended for the computation unit. Malicious manipulations of the hardware can be effected by shorting selected contacts, interrupting lines or by exposing the computation unit and/or a memory connected to the computation unit to laser radiation, for example. The cited error types can occur within the computation unit itself, within a memory which stores the program, within further components of a system which comprises the computation unit, or in electrical connections between the components of the computer system, for example. In order to detect such errors during the execution of the program, instruction flow control can be performed.
For the purpose of instruction flow control, a test value (the signature), which is obtained from the instructions of the program to the computation unit, is calculated, usually during the creation of the program. By way of example, the operation codes (opcodes) of the instructions can be added in order to form a checksum in this way. In the case of a linear program, which is usually executed from the start of the program to the end of the program, including all the instructions in between, it is therefore possible to calculate a single checksum (or more generally a test value) which can be checked at the end of the program or after the end of the program. For this check, in parallel with the execution of each instruction by the computation unit, the value of this instruction (for example in the form of the opcode available as a bit pattern) is set against the content of a specific register, e.g. is added to the register content or is Exclusive-Ored (XOR) with the register content on a bit-by-bit basis. As soon as all the instruction values have been taken into account in the specific register in this manner, the resulting value from the specific register can be compared with a reference test value in order to establish whether there is a match between the two values. If there is a match, proper execution of the program can usually be assumed, i.e. the program has actually been executed in the manner planned at the time of creation of the program. By way of example, the reference test value may be stored as a constant in the program code. Depending on how and with which programming language the program has been created, the reference test value can be calculated by a compiler and written into the program code.
Frequently, programs have branches in the program flow, which can also be regarded as “conditional jumps”. Following a branch, the program can be continued on at least two paths, the decision about which of the two or more possible paths is chosen being obtained only when the program is in runtime by virtue of the evaluation of a condition. It should be noted that branch points having more than two possible branch paths can normally be broken down into elemental branch points, i.e. into branch points which each have only two possible branch paths. For the value which is calculated while the program is in runtime, this means that it is dependent on which paths have been taken how often. So that, toward the end of the program, for example, or at another point within the program execution, a comparison can be performed between the current test value and a reference test value defined for this point, it is possible for the test values within the different paths which can be taken to be oriented to one another. This may take the form that the compiler incorporates into one path one or more instruction(s) which is (are) superfluous to the program execution per se and which alter(s) the test value such that said path has, at a merged point with another path, the same test value as this other path. Typically, there is then provision for specific updates to be recognized from particular bit patterns and to be filtered out of the normal instruction flow in order to be used for the update in a specific way.